package com.woniuxy.security.config;

import com.woniuxy.security.filter.JwtFilter;
import com.woniuxy.security.realm.DbRealm;
import com.woniuxy.security.realm.JwtRealm;
import com.woniuxy.security.realm.MultiRealmAuthenticatorRealm;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration //配置类注解
public class ShiroConfig {

    //1.配置realm：域对象
    @Bean
    public JwtRealm jwtRealm(){
        return new JwtRealm();
    }

    @Bean
    public DbRealm dbRealm(){return new DbRealm();}

    //2.自定义安全管理器
    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        /*
         * MultiRealmAuthenticator为自定义的realm处理器，
         * 原默认处理器为ModularRealmAuthenticator
         * 该类将shiro相关异常捕获未抛出，认证操作时，调用栈无法抓取认证抛出的异常，获得异常信息
         * 此处自定义继承其，并重写其处理异常的方法，抛出异常
         * */
        MultiRealmAuthenticatorRealm multiRealmAuthenticatorRealm = new MultiRealmAuthenticatorRealm();
        //向登录认证管理器中添加JwtRealm，分别用于初次登录和携带令牌访问
        multiRealmAuthenticatorRealm.setRealms(Arrays.asList(jwtRealm(),dbRealm()));
        /*
         * 当存在多个realm时,默认策略为一个realm认证不通过即不通过
         * AuthenticationStrategy为策略接口，其子类实现有一个抽象类和3个子类
         * 3个实现了的子类为：（见名知意）
         * AllSuccessfulStrategy；AtLeastOneSuccessFulStrategy;FirstSuccessfulStrategy
         * 此处新建一个new FirstSuccessfulStrategy()策略，采用第一个能通过认证的realm
         * 在自定义realm中使用supports()方法判断是否由当前realm进行认证
         * */
        multiRealmAuthenticatorRealm.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        //设置登录认证处理器为自定义的authenticator
        securityManager.setAuthenticator(multiRealmAuthenticatorRealm);
        //设置授权器为DbRealm
        return securityManager;
    }

    //3.shiro过滤器:主要来指定哪些请求需要认证、哪些不需要、哪些需要什么样的权限
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //配置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        //增加自定义过滤器
        Map<String, Filter>filterMap = new HashMap<>();
        filterMap.put("jwt",new JwtFilter());
        //添加自定义过滤器
        shiroFilterFactoryBean.setFilters(filterMap);
        //设置过滤器链
        //HashMap 无序   LinkedHashMap 有序
        Map<String,String> map = new LinkedHashMap<>();
        //设置过滤条件（需要过滤的uri，需要的过滤器类型）
        //设置/login请求直接放行（"anon"自带无需认证即可访问）
        map.put("/security/login","anon");
        map.put("security/auth","anon");
        map.put("/house/**","jwt");
        map.put("/order/**","jwt");
        map.put("/user/**","jwt");
        map.put("/broker/**","jwt");

        map.put("/security/test","jwt");

        //添加过滤器链map
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

}
